﻿using System;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNet.Identity;
using NHibernate.Identity.Internal;

namespace NHibernate.Identity
{
    public class RoleStore<TRole> : IRoleStore<TRole> where TRole : IdentityRole
    {
        private IEntityStore<TRole> _roleStore;
        private bool _disposed;

        public RoleStore(ISession session)
            : this(new EntityStore<TRole>(session))
        {
            if (session == null)
                throw new ArgumentNullException("session");

            Session = session;
        }

        internal RoleStore(IEntityStore<TRole> roleStore)
        {
            _roleStore = roleStore;
        }

        public ISession Session { get; private set; }

        private void ThrowIfDisposed()
        {
            if (_disposed)
                throw new ObjectDisposedException(GetType().Name);
        }

        public void Dispose()
        {
            _disposed = true;
            if (Session != null)
            {
                Session.Dispose();
                Session = null;
            }
            _roleStore = null;
        }

        public async Task CreateAsync(TRole role)
        {
            ThrowIfDisposed();
            if (role == null)
                throw new ArgumentNullException("role");

            await _roleStore.Save(role);
        }

        public async Task UpdateAsync(TRole role)
        {
            ThrowIfDisposed();
            if (role == null)
                throw new ArgumentNullException("role");

            await _roleStore.Save(role);
        }

        public async Task DeleteAsync(TRole role)
        {
            ThrowIfDisposed();
            if (role == null)
                throw new ArgumentNullException("role");

            await _roleStore.Delete(role);
        }

        public async Task<TRole> FindByIdAsync(string roleId)
        {
            ThrowIfDisposed();

            IQueryable<TRole> result = await _roleStore.Records();
            return result.SingleOrDefault(w => w.Id == roleId);
        }

        public async Task<TRole> FindByNameAsync(string roleName)
        {
            ThrowIfDisposed();

            IQueryable<TRole> result = await _roleStore.Records();
            return
                result.SingleOrDefault(w => String.Equals(w.Name, roleName, StringComparison.CurrentCultureIgnoreCase));
        }
    }
}